//
//  OPSmartTopics.m
//  OPFramework
//
//  Created by malcom on 7/20/08.
//  Copyright 2008 malcom-mac software. All rights reserved.
//

#import "OPSmartTopics.h"
#import "OPTopic.h"
#import "OPPageContainer.h"
#import "OPAuthUser.h"

#define _method_getActiveTopics			@"msgs.getActiveTopics"
#define _method_getUnansweredTopics		@"msgs.getUnansweredPosts"
#define _method_getNewsPostedMessage	@"msgs.getNewPostedMessagesFilteredBy"
#define _method_getRecentAnnouncements	@"msgs.getRecentsAnnouncements"
#define _method_getRecentHotTopics		@"msgs.getRecentsHotTopics"
#define _method_getBookmarkedTopics		@"user.getBookmarkedTopics"

typedef enum OPSmartTopic_Request {
    OPSmartTopic_Request_ActiveTopics		= 0,
    OPSmartTopic_Request_UnansweredTopics	= 1
} OPSmartTopic_Request;

typedef enum OPSmartTopic_CacheContentDRange {
    OPSmartTopic_CacheContentDRange_LastLogin		= 0,
    OPSmartTopic_CacheContentDRange_OtherDateRange	= 1
} OPSmartTopic_CacheContentDRange;


@implementation OPSmartTopics

@synthesize _activeTopics;
@synthesize _unansweredTopics;
@synthesize _hotTopics;
@synthesize _newTopicsSinceRefDate;
@synthesize _recentAnnouncements;
@synthesize _bookmarkedTopics;

- (id) initWithBoard:(OPBoard *) _board andListener:( NSObject <OPObject_AsyncResponse> *) _listener {
	self = [super initWithBoard: _board andListener: _listener];
	if (self != nil) {
		_activeTopics = [[OPPageContainer alloc] init];
		_unansweredTopics = [[OPPageContainer alloc] init];
		_hotTopics = [[OPPageContainer alloc] init];
		_newTopicsSinceRefDate = [[OPPageContainer alloc] init];
		_recentAnnouncements = [[OPPageContainer alloc] init];
		_bookmarkedTopics = [[OPPageContainer alloc] init];
		
		_int_whatCachedInNewTopics = -1;
		config_daysAgoToSearch = -1;
	}
	return self;
}

- (void) dealloc {
	[_activeTopics release];
	[_unansweredTopics release];
	[_hotTopics release];
	[_newTopicsSinceRefDate release];
	[_recentAnnouncements release];
	[_bookmarkedTopics release];
	[super dealloc];
}

- (NSString *) description {
	return [NSString stringWithFormat: @"OPSmartTopics: CACHE RESULTS ARE %d active topics pages, %d unanswered posts pages, %d hot topics listed, %d new topics pages",
							[_activeTopics.p_pagesContainer count],[_unansweredTopics.p_pagesContainer count],[[_hotTopics getPageAtIndex:0] count],[_newTopicsSinceRefDate.p_pagesContainer count]];
}

- (NSArray *) getHotTopics:(NSNumber *) _maxToList {
	if ([self isCacheExpired] || _hotTopics.p_totalElements == 0) { // if we want to get a new copy or we have not yet downloaded the page or the cache is expired
		[_hotTopics clear];
		[self sendXMLRequestForMethod: _method_getRecentHotTopics 
						   withParams: [NSArray arrayWithObject: _maxToList]
						parseSelector: @selector(_parseResponseTopicsList:)];
	}
	
	return [_hotTopics getPageAtIndex: 0]; // return the results (only in sync mode, otherwise it will return nil)
}

- (NSArray *) getUnansweredTopicsSinceDays:(NSNumber *) _daysAgo atPage:(NSNumber *) _pageIdx {
	[self _setDaysToSearch: _daysAgo forTable:_activeTopics];
	
	if ([self isCacheExpired] || [_activeTopics getPageAtIndex: _pageIdx] == nil) // if we want to get a new copy or we have not yet downloaded the page or the cache is expired
		[self sendXMLRequestForMethod: _method_getUnansweredTopics 
						   withParams: [NSArray arrayWithObjects:	@"topics",
										[NSNumber numberWithInt: config_daysAgoToSearch],
										_pageIdx,
										[_delegateBoard.obj_boardConfig getPropertyForKey: OPBoardConfig_TopicsPerPage],nil]
						parseSelector: @selector(_parseResponseTopicsList:)];
	
	return [_unansweredTopics getPageAtIndex: _pageIdx]; // return the results (only in sync mode, otherwise it will return nil)
}


- (NSArray *) getActiveTopicsSinceDays:(NSNumber *) _daysAgo atPage:(NSNumber *) _pageIdx {
	[self _setDaysToSearch: _daysAgo forTable:_activeTopics];
	
	if ([self isCacheExpired] || [_activeTopics getPageAtIndex: _pageIdx] == nil) // if we want to get a new copy or we have not yet downloaded the page or the cache is expired
		[self sendXMLRequestForMethod: _method_getActiveTopics
						   withParams: [NSArray arrayWithObjects:	[NSNumber numberWithInt: config_daysAgoToSearch],
										_pageIdx,
										[_delegateBoard.obj_boardConfig getPropertyForKey: OPBoardConfig_TopicsPerPage],nil]
						parseSelector: @selector(_parseResponseTopicsList:)];
	
	return [_activeTopics getPageAtIndex: _pageIdx]; // return the results (only in sync mode, otherwise it will return nil)
}

- (NSArray *) getNewTopicsFromDate:(NSCalendarDate *) _startDate endDate:(NSCalendarDate *) _endDate atPage:(NSNumber *) _pageIdx {
	// empty cache if previous content is a 'static range'
	if (_int_whatCachedInNewTopics != OPSmartTopic_CacheContentDRange_OtherDateRange) [_newTopicsSinceRefDate clear];
	return [self _getNewTopicsFromDate: _startDate endDate:_endDate atPage: _pageIdx];
}

- (NSArray *) getRecentAnnouncements:(NSNumber *) _maxElements {
	if ([self isCacheExpired] || _recentAnnouncements.p_totalElements == 0) {// if we want to get a new copy or we have not yet downloaded the page or the cache is expired
		[self sendXMLRequestForMethod: _method_getRecentAnnouncements
						   withParams: [NSArray arrayWithObjects: _maxElements,nil]
						parseSelector: @selector(_parseResponseTopicsList:)];
	}
	return [_recentAnnouncements getPageAtIndex: 0]; // return the results (only in sync mode, otherwise it will return nil)
	
}

- (NSArray *) getBookmarkedTopics {
	if ([self isCacheExpired] || _bookmarkedTopics.p_totalElements == 0) {// if we want to get a new copy or we have not yet downloaded the page or the cache is expired
		[self sendXMLRequestForMethod: _method_getBookmarkedTopics
						   withParams: [NSArray arrayWithObjects: [NSNumber numberWithUnsignedLongLong: [_delegateBoard.obj_authUser.user_loginDate timeIntervalSince1970]],
											[_delegateBoard.obj_boardConfig getPropertyForKey: OPBoardConfig_PostsPerPage], nil]
						parseSelector: @selector(_parseResponseTopicsList:)];
	}
	return [_bookmarkedTopics getPageAtIndex: [NSNumber numberWithInt: 0]]; // return the results (only in sync mode, otherwise it will return nil). bookmarked topics is available only in first page (not paginated)
	
}

- (NSArray *) getNewTopicsSinceLastLoginAtPage:(NSNumber *) _pageIdx {
	NSCalendarDate *_startDate = [[NSCalendarDate dateWithTimeIntervalSince1970: [_delegateBoard.obj_authUser.user_loginDate timeIntervalSince1970]] retain];
	NSCalendarDate *_endDate = [[NSCalendarDate date] retain];
	
	// empty cache if previous content is a 'static range'
	if (_int_whatCachedInNewTopics != OPSmartTopic_CacheContentDRange_LastLogin) [_newTopicsSinceRefDate clear];
	
	return [self _getNewTopicsFromDate: _startDate endDate:_endDate atPage: _pageIdx];
	
	[_startDate release];
	[_endDate release];
}

- (NSArray *) _getNewTopicsFromDate:(NSCalendarDate *) _startDate endDate:(NSCalendarDate *) _endDate atPage:(NSNumber *) _pageIdx {	
	if ([self isCacheExpired] || [_newTopicsSinceRefDate getPageAtIndex: _pageIdx] == nil) {// if we want to get a new copy or we have not yet downloaded the page or the cache is expired
			[self sendXMLRequestForMethod: _method_getNewsPostedMessage
										withParams: [NSArray arrayWithObjects:	
																	@"topics",
																	[_delegateBoard.obj_boardConfig getPropertyForKey: OPBoardConfig_TopicsPerPage],
																	_pageIdx,
																	[NSArray arrayWithObjects:		[_startDate descriptionWithCalendarFormat:@"%Y-%m-%d"] ,
																									[_endDate descriptionWithCalendarFormat:@"%Y-%m-%d"],nil], nil]
						parseSelector: @selector(_parseResponseTopicsList:)];
	}
	return [_newTopicsSinceRefDate getPageAtIndex: _pageIdx]; // return the results (only in sync mode, otherwise it will return nil)
	
}


- (void) _setDaysToSearch:(NSNumber *) _days forTable:(OPPageContainer *) _pageTable {
	// if days ago is different from your previous settings we will trash our data and get it from the scratch
	if (config_daysAgoToSearch == -1) config_daysAgoToSearch = [_days intValue];
	else if ([_days intValue] != config_daysAgoToSearch) [_pageTable clear];
}

// async response
- (void)connection: (XMLRPCConnection *)connection didReceiveResponse:(XMLRPCResponse *)response forMethod: (NSString *)method {	
	// super class check if it's an error, a numeric response or simply some data to parse
	if (![self _checkErrorInRawResponseFromServer: response forMethod:method]) {
		// data update to parse
		[self _parseResponseTopicsList: [NSArray arrayWithObjects: [response responseObject],method,nil]];
		// we can propagate the result to listeners
		[self dataUpdatedFor: self atMethod:method];	
	}
}

- (BOOL) _isNumericResponseFromServerAnErrorCode:(NSNumber *) _code forMethod:(NSString *) method {
	//switch ([_code intValue]) {
	
	//}
	return NO;
}

		
- (OPPageContainer *) _getTargetPageForMethod:(NSString *) _meth {
	if ([_meth isEqual: _method_getActiveTopics])			return _activeTopics;
	if ([_meth isEqual: _method_getUnansweredTopics])		return _unansweredTopics;
	if ([_meth isEqual: _method_getRecentAnnouncements])	return _recentAnnouncements;
	if ([_meth isEqual: _method_getNewsPostedMessage])		return _newTopicsSinceRefDate;
	if ([_meth isEqual: _method_getRecentHotTopics])		return _hotTopics;
	if ([_meth isEqual: _method_getBookmarkedTopics])		return _bookmarkedTopics;
	return nil;
}

- (void) _parseResponseTopicsList:(NSArray *) _result {
	NSDictionary *resultList = [_result objectAtIndex: 0];
	OPPageContainer *pageContainer = [self _getTargetPageForMethod: [_result objectAtIndex: 1]];
	
	NSMutableArray *p_cPageItems = [[NSMutableArray alloc] init];
	
	if (pageContainer != _hotTopics && pageContainer != _bookmarkedTopics) {
		// total pages
		pageContainer.p_totalPages = [[resultList objectForKey: @"total_pages"] intValue];
		// total items
		pageContainer.p_totalElements = [[resultList objectForKey: @"total_items"] intValue];
	} else {
		// hot topics and bookmarked topics are listed in a single page
		pageContainer.p_totalPages = 1;
		pageContainer.p_totalElements = [[resultList objectForKey: @"items"] count];
	}
	
	// parse items
	for (NSDictionary *cTopic in [resultList objectForKey: @"items"]) {
		OPForum *forum = [_delegateBoard.obj_boardStructure getForumFromID: [cTopic objectForKey: @"forum_id"]];
		if (forum != nil) {
			OPTopic *nTopic = [[OPTopic alloc] _initLinkedToForum: forum];
			nTopic.p_topicID = [[NSNumber numberWithInt: [[cTopic objectForKey: @"topic_id"] intValue]] retain];									// topic id
			nTopic.p_topicTitle = [[cTopic objectForKey: @"topic_title"] retain];																	// topic title
			nTopic.p_topicViews = [[NSNumber numberWithInt: [[cTopic objectForKey: @"topic_views"] intValue]] retain];								// number of views 
			nTopic.p_creationDate = [[NSDate dateWithTimeIntervalSince1970: [[cTopic objectForKey: @"topic_time"] longLongValue]] retain];			// creation date
			nTopic.p_topicReplies = [[NSNumber numberWithInt: [[cTopic objectForKey: @"topic_replies_real"] intValue]] retain];						// topic replies
			nTopic.p_lastPostDate = [[NSDate dateWithTimeIntervalSince1970: [[cTopic objectForKey: @"topic_last_post_time"] longLongValue]] retain];	// last post date
			nTopic._firstPostID = [[NSNumber numberWithInt: [[cTopic objectForKey: @"topic_first_post_id"] intValue]] retain];						// first post id
			nTopic._lastPostID = [[NSNumber numberWithInt: [[cTopic objectForKey: @"topic_last_post_id"] intValue]] retain];						// last post id
			nTopic.p_topicStatus = [[NSNumber numberWithInt: 0] retain]; // ??
			nTopic.p_lastViewDate = [[NSDate date] retain]; // ??
			nTopic.p_topicPassword = [[NSString alloc] init];
			nTopic.p_postAuthor = [[_delegateBoard.obj_membersCache getUserMemberFromID: [cTopic objectForKey: @"topic_poster"] withName:[cTopic objectForKey: @"topic_first_poster_name"]] retain];
			nTopic.p_lastPoster = [[_delegateBoard.obj_membersCache getUserMemberFromID: [cTopic objectForKey: @"topic_last_poster_id"] withName:[cTopic objectForKey: @"topic_last_poster_name"]] retain];

			// add to the list
			[p_cPageItems addObject: [nTopic autorelease]];
		}
	}
	
	if ([p_cPageItems count] > 0)
		[pageContainer addPage: p_cPageItems atIndex: [NSNumber numberWithInt: [[resultList objectForKey: @"page_showed"] intValue]]];
}

@end
